﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;

///<summary>
/// Abstract class for the turrets objects
/// 
/// inherited by : TurretBehaviour, TurretSAMBehaviour, TurretRotativeBehaviour
///</summary>
namespace Turret
{
    public abstract class Turret : MonoBehaviour
    {
        //Game objects
        private LevelMaster levelManager;
        protected StatManager statManager;
        public GameObject projectile;
        public GameObject detector;
        public Transform target;
        private GameObject placement;

        //Caracteristics
        public List<Stat> statTemplates;
        protected Stat currentStat;
        public Material radiusMaterial;

        protected float reloadTime;
        public float ReloadTime
        {
            get { return reloadTime; }
            set { reloadTime = value; }
        }
        protected float turnSpeed;
        public float TurnSpeed
        {
            get { return turnSpeed; }
            set { turnSpeed = value; }
        }
        protected float firePauseTime;
        public float FirePauseTime
        {
            get { return firePauseTime; }
            set { firePauseTime = value; }
        }
        protected float projectileRange;
        public float ProjectileRange
        {
            get { return projectileRange; }
            set { projectileRange = value; }
        }
        protected float projectileSpeed;
        public float ProjectileSpeed
        {
            get { return projectileSpeed; }
            set { projectileSpeed = value; }
        }
        protected float projectileDamage;
        public float ProjectileDamage
        {
            get { return projectileDamage; }
            set { projectileDamage = value; }
        }

        //Dynamic variables
        protected float nextFireTime;
        protected Quaternion desiredRotation;
        protected string[] targetableTag;
        protected GameObject radiusPlane;
        protected bool ghost = true;

        //GUI
        public GUIStyle menuStyle;
        private Vector2 menuOffset;
        private Vector2 hoverOffset;
        private Rect menuRectforHover;
        private Rect menuRectforBox;
        public GUIStyle upgradeInfoStyle;
        private Vector2 hoverInfoOffset;
        private Vector2 sellInfoOffset;
        private Vector2 sellOffset;
        private Vector2 buttonSize;
        private Vector2 upgradeOffset;

        private delegate void GUIMethod();
        private GUIMethod currentGUIMethod; 

        protected abstract void fire();

        protected virtual void Awake()
        {
            createRadiusPlane();
        }

		protected virtual void Start()
        {
            levelManager = GameObject.FindGameObjectWithTag("LevelMaster").GetComponent<LevelMaster>();
            targetableTag = new string[5];
            buttonSize = new Vector2(64, 20);
            menuOffset = new Vector2(20, 5);
            hoverOffset = new Vector2(50, 15);
            sellOffset = new Vector2(20, 128 - buttonSize.y);
            upgradeOffset = new Vector2(20 + 128 / 2, 128 - buttonSize.y);
            hoverInfoOffset = new Vector2(menuOffset.x + 128 + 10, menuOffset.y);

            //load stats
            statManager = GameObject.FindGameObjectWithTag("StatManager").GetComponent<StatManager>();
            getMyStatTemplates();
            currentStat = statTemplates[0];
            statManager.loadStat(this, currentStat);

            currentGUIMethod = turretIdle;
        }

        protected abstract void getMyStatTemplates();

        protected virtual void OnDestroy()
        {
            Destroy(radiusPlane);
        }


        protected virtual void Update()
        {
            if(ghost)
            {
                radiusPlane.transform.position = transform.position;
            }
        }

        void OnGUI()
        {
            if (currentGUIMethod != null)
                currentGUIMethod();
        }

        private void turretIdle()
        {

        }

        private void turretControlPanel()
        {
            Vector2 position = Camera.main.WorldToScreenPoint(transform.position);
            menuRectforHover = new Rect(position.x - hoverOffset.x, Screen.height - position.y - hoverOffset.y, 128 + hoverOffset.x, 128 + hoverOffset.y);
            menuRectforBox = new Rect(position.x + menuOffset.x, Screen.height - position.y + menuOffset.y, 128, 128);
            GUI.Box(menuRectforBox, new GUIContent("", "Box hover"), menuStyle);
            GUI.Label(new Rect(position.x + menuOffset.x + 10, Screen.height - position.y + menuOffset.y + 10, 108, 108), statManager.statToPrint(currentStat));

            if (GUI.Button(new Rect(position.x + sellOffset.x, Screen.height - position.y + sellOffset.y, buttonSize.x, buttonSize.y), new GUIContent("Sell", "Sell hover")))
            {
                sell();
            }

            if (!isLevelMax())
            {
                if (canBuyUpgrade())
                {
                    if (GUI.Button(new Rect(position.x + upgradeOffset.x, Screen.height - position.y + upgradeOffset.y, buttonSize.x, buttonSize.y), new GUIContent("Upgrade", "Upgrade stat")))
                    {
                        upgrade();
                        deselectMe();
                    }
                }
                else
                {
                    GUI.Label(new Rect(position.x + upgradeOffset.x, Screen.height - position.y + upgradeOffset.y, buttonSize.x, buttonSize.y), new GUIContent("Upgrade", "Upgrade price"));
                }
            }

            if (GUI.tooltip == "Upgrade stat")
            {
                Stat nextStat = nextUpgradeStat();
                GUI.Label(new Rect(position.x + hoverInfoOffset.x, Screen.height - position.y + hoverInfoOffset.y, 128, 128), statManager.statToPrint(nextStat), upgradeInfoStyle);
            }
            if (GUI.tooltip == "Upgrade price")
            {
                GUI.Label(new Rect(position.x + hoverInfoOffset.x, Screen.height - position.y + hoverInfoOffset.y, 128, 128), "Cost : " + upgradePrice());
            }
            if (GUI.tooltip == "Sell hover")
            {
                GUI.Label(new Rect(position.x + hoverInfoOffset.x, Screen.height - position.y + hoverInfoOffset.y, 128, 64), "\n\tSell for " + statManager.getBuildCost(currentStat) * 0.6, upgradeInfoStyle);
            }
            //Manages the mouse hover to make the turret menu disapear on click
            if(Input.GetMouseButton(0))
            {
                if (!menuRectforHover.Contains(new Vector2(Input.mousePosition.x, Screen.height - Input.mousePosition.y)))
                {
                    deselectMe();
                }
            }
        }

        private void createRadiusPlane()
        {
            float radius =  detector.GetComponent<SphereCollider>().radius;
            radiusPlane = (GameObject)GameObject.CreatePrimitive(PrimitiveType.Plane);
            radiusPlane.transform.position = transform.position;
            radiusPlane.transform.localScale = new Vector3(radius, 0, radius);
            radiusPlane.renderer.material = radiusMaterial;
            radiusPlane.renderer.enabled = false;
        }

        public void selectMe()
        {
            showRadius();
            currentGUIMethod = turretControlPanel;
        }

        public void deselectMe()
        {
            hideRadius();
            currentGUIMethod = turretIdle;
        }

        public void showRadius()
        {
            radiusPlane.renderer.enabled = true;
        }

        public void hideRadius()
        {
            radiusPlane.renderer.enabled = false;
        }
        
        public virtual bool canTarget(Collider collider)
        {
            if (target || ghost)
            {
                return false;
            }
            //Check the tag list for this collider
            for(int index = 0; index < targetableTag.Length; index++)
            {
                if (targetableTag[index] == collider.tag)
                {
                    return true;
                }
            }
            return false;
        }

        public virtual void setTarget(GameObject target)
        {
            //Update the target pointer and set ready to fire
            this.target = target.transform;
            nextFireTime = Time.time + (reloadTime / 2);
        }

        public virtual void targetOutOfRange(GameObject nTarget)
        {
            if (nTarget && nTarget == target)
            {
                target = null;
            }
        }

        public void setGhost(bool boule)
        {
            ghost = boule;
        }

        public void setActive(bool active)
        {
            gameObject.SetActive(active);
            radiusPlane.SetActive(active);
        }

        private void sell()
        {
            levelManager.sell(gameObject);
        }

        public void setPlacement(GameObject placement)
        {
            this.placement = placement;
        }

        public GameObject getPlacement()
        {
            return placement;
        }
        
        public void setReloadTime(float time)
        {
            reloadTime = time;
        }

        public void setTurnSpeed(float speed)
        {
            turnSpeed = speed;
        }

        public void setFirePauseTime(float time)
        {
            firePauseTime = time;
        }

        public void setProjectileRange(float range)
        {
            projectileRange = range;
        }

        public void setProjectileSpeed(float speed)
        {
            projectileSpeed = speed;
        }
        
        public void setProjectileDamage(float dmg)
        {
            projectileDamage = dmg;
        }

        public Stat getCurrentStat()
        {
            return currentStat;
        }

        private void upgrade()
        {
            currentStat = nextUpgradeStat();
            statManager.loadStat(this, currentStat);
            levelManager.spendChash(currentStat.UpgradePrice);
        }

        private bool canBuyUpgrade()
        {
            return levelManager.canBuy(upgradePrice());
        }

        private int upgradePrice()
        {
            return nextUpgradeStat().UpgradePrice;
        }

        private Stat nextUpgradeStat()
        {
            int index = statTemplates.IndexOf(currentStat) + 1;
            return statTemplates[index];
        }

        private bool isLevelMax()
        {
            return ((statTemplates.Count - 1) == statTemplates.IndexOf(currentStat));
        }
    }
}
